package main

import (
	"fmt"
	"net"
	"time"
)
type Client struct {
	C chan string
	Name string
	Addr string
}
var onlineUser map[string]Client
var message = make(chan string)
var isQuit = make(chan bool)
var hasData = make(chan bool)
func Manager()  {
	for{
		msg := <- message
		for _, cli := range onlineUser{
			cli.C <- msg
		}
		//fmt.Println(msg)
	}

}
func sendMessage(conn net.Conn, cli Client)  {
	for msg := range cli.C{
		conn.Write([]byte(msg + "\n"))
	}
}

func HandleConn(conn net.Conn)  {
	addr:=conn.RemoteAddr().String()
	cli := Client{make(chan string),addr,addr}
	onlineUser[addr] = cli
	fmt.Println("onlineUser:", onlineUser[addr])
	message <- "[" + addr +"] become online"

	go sendMessage(conn, cli)
	go func() {
		buf:=make([]byte,1024)
		for{
			n,errRead:=conn.Read(buf)
			if n==0{
				fmt.Println("tuichu n=0")
				isQuit <- true
				fmt.Println("Read Err:",errRead)
				return
			}
			//if errRead!=nil{
			//	fmt.Println("nnnnnn")
			//	fmt.Println("Read1 Err:",errRead)
			//	return
			//}
            mm := string(buf[:n-1])
			fmt.Println("buf:",string(mm))
			if len(mm)==3 && mm=="who" {
				conn.Write([]byte("user list:\n"))
				for _, tmp := range onlineUser {
					content := "[" + tmp.Addr + "]:" + tmp.Name + "\n"
					conn.Write([]byte(content))
				}
			}else if len(mm)==6 && mm=="revise"{
				conn.Write([]byte("Please input your username:"))
				nn,errRead:=conn.Read(buf)
				if errRead!=nil{
					fmt.Println("Read Err:",errRead)
					return
				}
				cli.Name = string(buf[:nn-1])
				onlineUser[addr] = cli
				conn.Write([]byte("Revise Name OK"))

			}else{
				cliMessage:= "[" + addr + "] " + cli.Name + ":" + mm
				message <- cliMessage
			}
			hasData <- true
		}
	}()
	for{
		select {
        case <-isQuit:
            delete(onlineUser,addr)
			message <- addr + ":login out"
        	return
		case <-hasData:

		case <-time.After(20*time.Second):
			delete(onlineUser,addr)
			message <- addr + ": time out leave"
			return
		}
	}
}
func main()  {
	listener,errListen:=net.Listen("tcp","127.0.0.1:8000")
	defer listener.Close()
	if errListen!=nil{
		fmt.Println("Listen Err:",errListen)
		return
	}
	onlineUser = make(map[string]Client)
	go Manager()
	for{
		conn,errConn:=listener.Accept()
		if errConn!=nil{
			fmt.Println("Accept Err:",errConn)
			return
		}
		go HandleConn(conn)
	}
}